/*
 * Created by Jaren at 2023/9/25 11:13
 */
import 'dart:typed_data';

import 'package:inmotion_protocol/util/byte_util.dart';

import 'dart:math' as math;

class ElephantUtil {
  /// 计算校验和
  static Uint8ClampedList calSumCheck(Uint8ClampedList bytes, {int offset = 0, int? length}) {
    length ??= bytes.length - offset;
    int sum = 0x0000;
    for (var i = offset; i < offset + length; i++) {
      sum += (bytes[i] & 0xFF);
    }
    sum &= 0xFFFF;
    // 与0xFFFF异或
    sum ^= 0xFFFF;
    return ByteUtil.num2BytesLe(sum, 2);
  }

  /// 协议中的 `color index` 转为 RGB 颜色<br/>
  /// color index 范围为 [1 - 240]，均匀对应 HSV 颜色 hue 值 [0 - 360]
  static int colorIndex2Color(int colorIndex) {
    if (colorIndex == 240) colorIndex = 0;
    return _HSVColor.fromAHSV(1, (colorIndex / 240 * 360).toInt().toDouble(), 1, 1).toColor();
  }

  static int color2ColorIndex(int color) {
    return (_HSVColor.fromColor(color).hue / 360 * 240).round();
  }

  /// 判断当前灯效模式是否支持 DIY 颜色
  static bool isLightEffectModeSupportDiyColor(int mode) {
    return mode == 1 || mode == 5;
  }
}

/// The implementation of [_ColorUtil] and [_HSVColor] are copied from flutter core lib
/// to keep the inmotion_protocol lib as a pure dart package.

/// Copied from package: flutter\lib\src\painting\colors.dart
class _ColorUtil {
  static double _getHue(double red, double green, double blue, double max, double delta) {
    late double hue;
    if (max == 0.0) {
      hue = 0.0;
    } else if (max == red) {
      hue = 60.0 * (((green - blue) / delta) % 6);
    } else if (max == green) {
      hue = 60.0 * (((blue - red) / delta) + 2);
    } else if (max == blue) {
      hue = 60.0 * (((red - green) / delta) + 4);
    }

    /// Set hue to 0.0 when red == green == blue.
    hue = hue.isNaN ? 0.0 : hue;
    return hue;
  }

  static int _colorFromHue(
    double alpha,
    double hue,
    double chroma,
    double secondary,
    double match,
  ) {
    double red;
    double green;
    double blue;
    if (hue < 60.0) {
      red = chroma;
      green = secondary;
      blue = 0.0;
    } else if (hue < 120.0) {
      red = secondary;
      green = chroma;
      blue = 0.0;
    } else if (hue < 180.0) {
      red = 0.0;
      green = chroma;
      blue = secondary;
    } else if (hue < 240.0) {
      red = 0.0;
      green = secondary;
      blue = chroma;
    } else if (hue < 300.0) {
      red = secondary;
      green = 0.0;
      blue = chroma;
    } else {
      red = chroma;
      green = 0.0;
      blue = secondary;
    }
    int a = (alpha * 0xFF).round();
    int r = ((red + match) * 0xFF).round();
    int g = ((green + match) * 0xFF).round();
    int b = ((blue + match) * 0xFF).round();

    return (a << 24) | (r << 16) | (g << 8) | b;
  }
}

/// Copied from package: flutter\lib\src\painting\colors.dart
class _HSVColor {
  const _HSVColor.fromAHSV(this.alpha, this.hue, this.saturation, this.value)
      : assert(alpha >= 0.0),
        assert(alpha <= 1.0),
        assert(hue >= 0.0),
        assert(hue <= 360.0),
        assert(saturation >= 0.0),
        assert(saturation <= 1.0),
        assert(value >= 0.0),
        assert(value <= 1.0);

  factory _HSVColor.fromColor(int argb) {
    final double alpha = ((argb & 0xFF000000) >> 24) / 0xFF;
    final double red = ((argb & 0x00FF0000) >> 16) / 0xFF;
    final double green = ((argb & 0x0000FF00) >> 8) / 0xFF;
    final double blue = (argb & 0x000000FF) / 0xFF;

    final double max = math.max(red, math.max(green, blue));
    final double min = math.min(red, math.min(green, blue));
    final double delta = max - min;

    final double hue = _ColorUtil._getHue(red, green, blue, max, delta);
    final double saturation = max == 0.0 ? 0.0 : delta / max;

    return _HSVColor.fromAHSV(alpha, hue, saturation, max);
  }

  final double alpha;
  final double hue;
  final double saturation;
  final double value;

  int toColor() {
    final double chroma = saturation * value;
    final double secondary = chroma * (1.0 - (((hue / 60.0) % 2.0) - 1.0).abs());
    final double match = value - chroma;

    return _ColorUtil._colorFromHue(alpha, hue, chroma, secondary, match);
  }
}
